package gormplus

import (
	"database/sql"
	"github.com/guregu/null/v5"
	"github.com/hlhutu/gormplus/utils"
	"github.com/shopspring/decimal"
	"reflect"
	"strings"
	"unicode"
)

// NullableValue 如果是指针类型，可能会返回nil
// 如果不是指针，但是 null 包或者 sql.Null系列，也可能会返回nil
// 另外，0值直接返回nil
func NullableValue(v reflect.Value) any {
	if v.Kind() == reflect.Ptr { // 如果是指针
		if v.IsNil() { // 空指针直接返回nil
			return nil
		} else { // 返回解引用之后的值
			v = v.Elem()
		}
	}
	if v.IsZero() {
		return nil
	}
	switch v.Kind() {
	case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
		return v.Int()
	case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64:
		return v.Uint()
	case reflect.Float32, reflect.Float64:
		return v.Float()
	case reflect.String:
		return v.String()
	case reflect.Bool:
		return v.Bool()
	case reflect.Slice:
		return v.Interface()
	case reflect.Map:
		return v.Interface()
	case reflect.Struct:
		// 先处理看是不是null包的类型
		if result, ok := processForNull(v.Interface()); ok {
			return result
		}
		return v.Interface()
	default:
		return "unsupported type"
	}
}

// 判断是不是null包里面的类型，共9种类型
// 如果是null包，并且是 !valid就会返回nil
func processForNull(v any) (any, bool) {
	if i, ok := v.(null.Int); ok {
		if i.Valid {
			return i, ok
		} else {
			return nil, ok
		}
	}
	if i, ok := v.(null.Int16); ok {
		if i.Valid {
			return i, ok
		} else {
			return nil, ok
		}
	}
	if i, ok := v.(null.Int32); ok {
		if i.Valid {
			return i, ok
		} else {
			return nil, ok
		}
	}
	if i, ok := v.(null.Int64); ok {
		if i.Valid {
			return i, ok
		} else {
			return nil, ok
		}
	}
	if i, ok := v.(null.Float); ok {
		if i.Valid {
			return i, ok
		} else {
			return nil, ok
		}
	}
	if i, ok := v.(null.Byte); ok {
		if i.Valid {
			return i, ok
		} else {
			return nil, ok
		}
	}
	if i, ok := v.(null.Bool); ok {
		if i.Valid {
			return i, ok
		} else {
			return nil, ok
		}
	}
	if i, ok := v.(null.String); ok {
		if i.Valid {
			return i, ok
		} else {
			return nil, ok
		}
	}
	if i, ok := v.(null.Time); ok {
		if i.Valid {
			return i, ok
		} else {
			return nil, ok
		}
	}
	// sql包8个 4个int+float+bool+string+time
	if i, ok := v.(sql.NullByte); ok {
		if i.Valid {
			return i, ok
		} else {
			return nil, ok
		}
	}
	if i, ok := v.(sql.NullInt16); ok {
		if i.Valid {
			return i, ok
		} else {
			return nil, ok
		}
	}
	if i, ok := v.(sql.NullInt32); ok {
		if i.Valid {
			return i, ok
		} else {
			return nil, ok
		}
	}
	if i, ok := v.(sql.NullInt64); ok {
		if i.Valid {
			return i, ok
		} else {
			return nil, ok
		}
	}
	if i, ok := v.(sql.NullFloat64); ok {
		if i.Valid {
			return i, ok
		} else {
			return nil, ok
		}
	}
	if i, ok := v.(sql.NullBool); ok {
		if i.Valid {
			return i, ok
		} else {
			return nil, ok
		}
	}
	if i, ok := v.(sql.NullString); ok {
		if i.Valid {
			return i, ok
		} else {
			return nil, ok
		}
	}
	if i, ok := v.(sql.NullTime); ok {
		if i.Valid {
			return i, ok
		} else {
			return nil, ok
		}
	}
	if i, ok := v.(decimal.NullDecimal); ok {
		if i.Valid {
			return i, ok
		} else {
			return nil, ok
		}
	}
	return nil, false
}

// 获取标签中的某个子标签值
func getTagValue(str string, child string) string {
	splits := strings.Split(str, ";")
	for _, s := range splits {
		s1 := strings.TrimSpace(s)
		arr := strings.Split(s1, ":")
		if len(arr) > 1 && strings.TrimSpace(arr[0]) == child {
			return strings.TrimSpace(arr[1])
		}
	}
	return ""
}

// CheckPage 分页参数做容错处理，页码从1开始
func CheckPage(page *Page) {
	if page.PageSize < 0 {
		page.PageSize = 10 // 默认每页10条
	}
	if page.PageNum <= 0 {
		page.PageNum = 1 // 页码从1开始
	}
	page.Total = 0
}

// ToNullableMap 对象转化为map，空的字段
func ToNullableMap(t any) map[string]any {
	maps := make(map[string]any)
	utils.Reflect().EachStruct(t, func(f reflect.StructField, t reflect.Type, value reflect.Value) bool {
		getValue := NullableValue(value)
		if getValue == nil {
			return true
		}
		// 获取gorm标签
		fieldName := f.Tag.Get("gorm")
		if fieldName != "" {
			fieldName = getTagValue(fieldName, "column")
		}
		if fieldName == "" { // 如果没获取到，就自动转换
			fieldName = ToSnakeCase(f.Name)
		}
		if fieldName != "" { // 获取不到就忽略字段
			maps[fieldName] = getValue
		}
		return true
	})
	return maps
}

// ToSnakeCase 将驼峰命名转换为蛇形命名
// 例如: "UserName" -> "user_name", "APIResponse" -> "api_response"
func ToSnakeCase(s string) string {
	if s == "" {
		return ""
	}

	var result strings.Builder
	result.Grow(len(s) + 10) // 预分配内存，避免多次扩容

	for i, r := range s {
		// 如果是大写字母
		if unicode.IsUpper(r) {
			// 如果不是第一个字符且前一个字符不是下划线，添加下划线
			if i > 0 && s[i-1] != '_' {
				// 特殊情况：如果前一个字符是小写，或者后面还有字符且是小写，添加下划线
				if i > 0 && unicode.IsLower(rune(s[i-1])) ||
					(i+1 < len(s) && unicode.IsLower(rune(s[i+1]))) {
					result.WriteByte('_')
				}
			}
			// 转为小写并添加
			result.WriteRune(unicode.ToLower(r))
		} else {
			// 直接添加小写字符
			result.WriteRune(r)
		}
	}

	return result.String()
}
